package sql.constraints;

import java.util.ArrayList;
import java.util.HashMap; // Added for deep copy of column meta
import java.util.List;
import java.util.Map; // For tableColumnNames list

public class ConstraintUtils {

    /**
     * 简单的验证结果类。
     */
    public static class ValidationResult {
        public final boolean isValid;
        public final String errorMessage;

        private ValidationResult(boolean isValid, String errorMessage) {
            this.isValid = isValid;
            this.errorMessage = errorMessage;
        }

        public static ValidationResult valid() {
            return new ValidationResult(true, null);
        }

        public static ValidationResult invalid(String message) {
            return new ValidationResult(false, message);
        }
    }

    /**
     * 用于封装准备添加约束时的变更结果。
     */
    public static class PrepareConstraintChangesResult {
        public final boolean isValid;
        public final String errorMessage;
        // 包含 newConstraint 以及任何自动生成的约束 (如 PK 附带的 NOT NULL)
        public final List<TableConstraint> constraintsToAdd; 
        // 需要更新 'nullable' 标志的列元数据列表
        // 或者也可以只返回需要更新的列名列表，由 TableManager 自行更新
        // 为简单起见，这里假设 TableManager 会根据 constraintsToAdd 中的 NOT_NULL 来更新
        public final List<Map<String, Object>> updatedColumnMetaList; // 可以是修改后的完整列表，或null表示无变化

        private PrepareConstraintChangesResult(boolean isValid, String errorMessage, List<TableConstraint> constraintsToAdd, List<Map<String, Object>> updatedColumnMetaList) {
            this.isValid = isValid;
            this.errorMessage = errorMessage;
            this.constraintsToAdd = constraintsToAdd != null ? constraintsToAdd : new ArrayList<>();
            this.updatedColumnMetaList = updatedColumnMetaList; // Can be null if no direct changes by this method
        }

        public static PrepareConstraintChangesResult success(List<TableConstraint> constraintsToAdd, List<Map<String, Object>> updatedColumnMetaList) {
            return new PrepareConstraintChangesResult(true, null, constraintsToAdd, updatedColumnMetaList);
        }
        
        public static PrepareConstraintChangesResult success(List<TableConstraint> constraintsToAdd) {
            return new PrepareConstraintChangesResult(true, null, constraintsToAdd, null);
        }

        public static PrepareConstraintChangesResult failure(String message) {
            return new PrepareConstraintChangesResult(false, message, null, null);
        }
    }

    /**
     * 校验新的约束名称是否与现有约束名称冲突。
     * @param newConstraintName 要校验的新约束名称。
     * @param existingConstraints 表中已存在的约束列表。
     * @return ValidationResult 包含校验结果。
     */
    public static ValidationResult validateConstraintName(String newConstraintName, List<TableConstraint> existingConstraints) {
        if (newConstraintName == null || newConstraintName.trim().isEmpty()) {
            return ValidationResult.invalid("约束名称不能为空。");
        }
        for (TableConstraint ec : existingConstraints) {
            if (ec.getName().equalsIgnoreCase(newConstraintName)) {
                return ValidationResult.invalid("约束名称 [" + newConstraintName + "] 已存在。");
            }
        }
        return ValidationResult.valid();
    }

    /**
     * 校验约束中定义的所有列是否存在于表的列元数据中。
     * @param constraintColumns 约束中定义的列名列表。
     * @param constraintType 约束类型。
     * @param columnMetaList 表的列元数据列表 (List<Map<String, Object>>，每个Map包含 "name", "type", "length"等)。
     * @param tableName 表名 (用于错误消息)。
     * @param constraintName 约束名 (用于错误消息)。
     * @return ValidationResult 包含校验结果。
     */
    public static ValidationResult validateConstraintColumns(
            List<String> constraintColumns, // Columns explicitly listed in the TableConstraint object
            ConstraintType constraintType,  // The type of the constraint being validated
            List<Map<String, Object>> columnMetaList, // Actual columns from table metadata
            String tableName, 
            String constraintName) {

        if (constraintType == ConstraintType.CHECK) {
            // For CHECK constraints, the TableConstraint.columns list might be empty (for table-level CHECKs).
            // The actual columns involved are in the checkExpression.
            // If constraintColumns IS provided (e.g., from a column-level CHECK parsing), then those must exist.
            // A more advanced validation would parse checkExpression to find all referenced columns
            // and check their existence here. For now, if constraintColumns is empty, we assume it's okay
            // for a CHECK constraint, and rely on expression evaluation at runtime for column errors.
            if (constraintColumns == null || constraintColumns.isEmpty()) {
                return ValidationResult.valid(); 
            }
            // If constraintColumns is not empty for a CHECK, proceed to validate them.
        }

        // For other types (or if CHECK has explicit columns listed in TableConstraint.columns)
        if (constraintColumns == null || constraintColumns.isEmpty()) {
            // Which types ABSOLUTELY require columns in their TableConstraint.columns list?
            if (constraintType == ConstraintType.PRIMARY_KEY || 
                constraintType == ConstraintType.UNIQUE || 
                constraintType == ConstraintType.NOT_NULL ||
                constraintType == ConstraintType.FOREIGN_KEY) { // FK also needs its own columns defined
                return ValidationResult.invalid("约束 [" + constraintName + "] 类型 " + constraintType + " 必须指定列。");
            }
            return ValidationResult.valid(); // Other types might not require explicit columns here
        }

        // Existing logic to validate that each column in constraintColumns exists in tableColumnMetaList
        List<String> actualTableColumnNames = new ArrayList<>();
        if (columnMetaList != null) {
            for (Map<String, Object> colMeta : columnMetaList) {
                if (colMeta != null && colMeta.get("name") instanceof String) {
                    actualTableColumnNames.add((String) colMeta.get("name"));
                }
            }
        }

        for (String constrainedColName : constraintColumns) {
            if (constrainedColName == null || constrainedColName.trim().isEmpty()){
                 return ValidationResult.invalid("约束 [" + constraintName + "] 中的列名不能为空。");
            }
            boolean found = false;
            for(String tableColNameFromMeta : actualTableColumnNames){
                if(tableColNameFromMeta.equalsIgnoreCase(constrainedColName)){
                    found = true;
                    break;
                }
            }
            if (!found) {
                return ValidationResult.invalid("约束 [" + constraintName + "] 中指定的列 [" + constrainedColName + "] 不存在于表 [" + tableName + "]。");
            }
        }
        return ValidationResult.valid();
    }

    /**
     * 准备并校验一个新约束的添加操作。
     * 此方法会检查名称、列、类型特定逻辑 (如主键唯一性)，并准备最终要添加的约束列表
     * (可能包括因主键而自动生成的 NOT NULL 约束)。
     *
     * @param newConstraint 要添加的新约束。
     * @param existingConstraints 表中已存在的约束列表。
     * @param originalColumnMetaList 原始的列元数据列表。
     * @param tableName 表名。
     * @return PrepareConstraintChangesResult 包含操作结果和必要的变更。
     */
    public static PrepareConstraintChangesResult prepareConstraintForAddition(
            TableConstraint newConstraint,
            List<TableConstraint> existingConstraints,
            List<Map<String, Object>> originalColumnMetaList, // 传入原始的，方法内部可以创建副本修改
            String tableName) {

        // 1. 基础校验：名称和列
        ValidationResult nameValidation = validateConstraintName(newConstraint.getName(), existingConstraints);
        if (!nameValidation.isValid) {
            return PrepareConstraintChangesResult.failure(nameValidation.errorMessage);
        }

        ValidationResult columnsValidation = validateConstraintColumns(newConstraint.getColumns(), newConstraint.getType(), originalColumnMetaList, tableName, newConstraint.getName());
        if (!columnsValidation.isValid) {
            return PrepareConstraintChangesResult.failure(columnsValidation.errorMessage);
        }

        List<TableConstraint> constraintsToAdd = new ArrayList<>();
        List<Map<String, Object>> potentiallyModifiedColumnMeta = new ArrayList<>();
        for (Map<String, Object> meta : originalColumnMetaList) { // 深拷贝列元数据以便修改
            potentiallyModifiedColumnMeta.add(new HashMap<>(meta));
        }
        boolean columnMetaWasModified = false;

        // 2. 类型特定校验和处理
        switch (newConstraint.getType()) {
            case PRIMARY_KEY:
                // a. 检查是否已存在主键
                for (TableConstraint ec : existingConstraints) {
                    if (ec.getType() == ConstraintType.PRIMARY_KEY) {
                        return PrepareConstraintChangesResult.failure("表 [" + tableName + "] 已存在主键 [" + ec.getName() + "]。在关系数据库中，一个表只能有一个主键（可以是单列或由多列组成的复合主键）。如需添加更多唯一标识，请考虑使用UNIQUE约束。");
                    }
                }
                constraintsToAdd.add(newConstraint); // 添加主键约束本身

                // b. 为主键列自动添加 NOT NULL 约束 (如果尚不存在) 并更新列元数据
                for (String pkColName : newConstraint.getColumns()) {
                    boolean nnConstraintExistsForPkCol = false;
                    // 检查是否已存在显式的 NOT NULL 约束 (在现有约束中)
                    for (TableConstraint ec : existingConstraints) {
                        if (ec.getType() == ConstraintType.NOT_NULL && ec.getColumns().contains(pkColName)) {
                            nnConstraintExistsForPkCol = true;
                            break;
                        }
                    }
                    // 检查是否已在新添加的约束列表中 (主要针对组合主键的多列，确保不重复添加NN)
                    if(!nnConstraintExistsForPkCol){
                        for (TableConstraint tcAdded : constraintsToAdd) { // 检查已加入 constraintsToAdd 的，不包括当前 newConstraint (PK本身)
                             if (tcAdded.getType() == ConstraintType.NOT_NULL && tcAdded.getColumns().contains(pkColName)) {
                                nnConstraintExistsForPkCol = true;
                                break;
                            }
                        }
                    }

                    if (!nnConstraintExistsForPkCol) {
                        TableConstraint nnForPkCol = new TableConstraint(
                                "nn_" + tableName + "_" + pkColName, // 考虑生成更唯一的名称或让用户指定
                                ConstraintType.NOT_NULL,
                                java.util.Collections.singletonList(pkColName)
                        );
                        constraintsToAdd.add(nnForPkCol); // 添加到这个方法作用域的待添加列表
                        // 更新列元数据的 nullable 标志
                        for (Map<String, Object> colMeta : potentiallyModifiedColumnMeta) {
                            if (pkColName.equalsIgnoreCase((String)colMeta.get("name"))) {
                                colMeta.put("nullable", false);
                                columnMetaWasModified = true;
                                break;
                            }
                        }
                    }
                }
                break;

            case UNIQUE:
                // 可以添加对重复 UNIQUE 约束的检查 (相同列集)
                // 例如: 查找 existingConstraints 中是否有其他 UNIQUE 约束作用于完全相同的列集合。
                // for (TableConstraint ec : existingConstraints) {
                //    if (ec.getType() == ConstraintType.UNIQUE && new HashSet<>(ec.getColumns()).equals(new HashSet<>(newConstraint.getColumns()))) {
                //        return PrepareConstraintChangesResult.failure("表 [" + tableName + "] 已存在针对列 " + newConstraint.getColumns() + " 的唯一约束 [" + ec.getName() + "]。");
                //    }
                // }
                constraintsToAdd.add(newConstraint);
                break;

            case NOT_NULL:
                // TableConstraint构造函数已检查NOT_NULL只能有一列
                // 此处主要用于将其加入待添加列表，并确保对应列元数据更新
                if(newConstraint.getColumns().size() != 1){
                     // 此检查理论上 TableConstraint 构造函数已覆盖，但作为防御性检查
                     return PrepareConstraintChangesResult.failure("NOT_NULL 约束 ["+newConstraint.getName()+"] 必须且只能应用于一个列。");
                }
                String nnCol = newConstraint.getColumns().get(0);
                for (Map<String, Object> colMeta : potentiallyModifiedColumnMeta) {
                    if (nnCol.equalsIgnoreCase((String)colMeta.get("name"))) {
                        colMeta.put("nullable", false);
                        columnMetaWasModified = true;
                        break;
                    }
                }
                constraintsToAdd.add(newConstraint);
                break;
            
            case FOREIGN_KEY:
                // TODO: 添加外键特定校验 (如引用的表/列是否存在)
                constraintsToAdd.add(newConstraint);
                System.out.println("ℹ️ FOREIGN KEY 约束 [" + newConstraint.getName() + "] 的详细校验尚未实现。");
                break;

            case CHECK:
                // TODO: 添加 CHECK 约束特定校验 (如表达式的有效性)
                constraintsToAdd.add(newConstraint);
                System.out.println("ℹ️ CHECK 约束 [" + newConstraint.getName() + "] 的详细校验尚未实现。");
                break;

            default:
                return PrepareConstraintChangesResult.failure("不支持的约束类型: " + newConstraint.getType());
        }

        return PrepareConstraintChangesResult.success(constraintsToAdd, columnMetaWasModified ? potentiallyModifiedColumnMeta : null);
    }

    /**
     * Generates the standard name for an automatically created NOT NULL constraint 
     * associated with a PRIMARY KEY column.
     * @param columnName The name of the column that is part of the primary key.
     * @param pkConstraintName The name of the primary key constraint.
     * @return The generated name for the NOT NULL constraint.
     */
    public static String generateAutoNotNullConstraintName(String columnName, String pkConstraintName) {
        return "constraint_NN_" + columnName + "_for_PK_" + pkConstraintName;
    }

    // 未来可以添加更多方法，例如:
    // public static ValidationResult validatePrimaryKeyAddition(TableConstraint newPkConstraint, List<TableConstraint> existingConstraints, String tableName)
    // public static PrepareConstraintChangesResult prepareConstraintChanges(TableConstraint newConstraint, List<TableConstraint> existingConstraints, List<Map<String, Object>> columnsMetaList, String tableName)
    // PrepareConstraintChangesResult 可以包含:
    // - List<TableConstraint> constraintsToAdd (包括 newConstraint 和任何自动生成的约束如 NOT NULL for PK)
    // - List<String> columnsToMarkNotNull (列名列表，其元数据中的 'nullable' 需要更新)
    // - boolean isValid
    // - String errorMessage
} 